package com.ionehe.group.common.zzd.session;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.xxpt.gateway.shared.api.request.OapiChatGroupV2CreateRequest;
import com.alibaba.xxpt.gateway.shared.api.request.OapiChatSendMsgRequest;
import com.alibaba.xxpt.gateway.shared.api.request.OapiTcV2OpenapiTaskCreateJsonRequest;
import com.alibaba.xxpt.gateway.shared.api.response.OapiCalendarCreateCalendarResponse;
import com.alibaba.xxpt.gateway.shared.api.response.OapiChatGroupV2CreateResponse;
import com.alibaba.xxpt.gateway.shared.api.response.OapiChatSendMsgResponse;
import com.alibaba.xxpt.gateway.shared.api.response.OapiTcV2OpenapiTaskCreateJsonResponse;
import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
import com.alibaba.xxpt.gateway.shared.client.http.GetClient;
import com.alibaba.xxpt.gateway.shared.client.http.IntelligentGetClient;
import com.alibaba.xxpt.gateway.shared.client.http.PostClient;
import com.ionehe.group.common.zzd.dto.ZzdContent;
import com.ionehe.group.common.zzd.dto.ZzdResponse;
import com.google.common.base.Preconditions;

import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import cn.hutool.core.util.StrUtil;
import com.ionehe.group.common.zzd.config.base.ZzdConfig;
import com.ionehe.group.common.zzd.config.zzd.ChatType;
import com.ionehe.group.common.zzd.config.zzd.GroupManagementType;
import com.ionehe.group.common.zzd.config.zzd.QueryStatus;
import com.ionehe.group.common.zzd.config.zzd.ZzdGlobalConfig;
import com.ionehe.group.common.zzd.dto.CreateGroupDto;
import com.ionehe.group.common.zzd.dto.CreateTaskDto;
import com.ionehe.group.common.zzd.dto.GetZzdUserDto;
import com.ionehe.group.common.zzd.dto.Pair;
import com.ionehe.group.common.zzd.dto.SendChatMessageDto;
import com.ionehe.group.common.zzd.dto.ZzdTextMessage;
import com.ionehe.group.common.zzd.resp.AccessToken;
import com.ionehe.group.common.zzd.resp.AddressBookScope;
import com.ionehe.group.common.zzd.resp.ZzdAccount;
import com.ionehe.group.common.zzd.resp.ZzdEmployee;
import com.ionehe.group.common.zzd.resp.ZzdOrganization;
import com.ionehe.group.common.zzd.resp.ZzdTicket;
import com.ionehe.group.common.zzd.resp.ZzdUserAccount;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

@Component
public class ZzdSession {
    private static final Logger log = LoggerFactory.getLogger(ZzdSession.class);
    private ExecutableClient zzdLoginClient;
    private ExecutableClient zzdClient;
    private ZzdConfig zzdConfig;

    public ZzdSession(ZzdConfig zzdConfig) {
        this.zzdConfig = zzdConfig;
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdLoginAccessKey), "zzdLoginAccessKey can't be blank, check your application.properties.");
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdLoginSecretKey), "zzdLoginSecretKey can't be blank, check your application.properties.");
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdAccessKey), "zzdAccessKey can't be blank, check your application.properties.");
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdSecretKey), "zzdSecretKey can't be blank, check your application.properties.");
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdDomainName), "zzdDomainName can't be blank, check your application.properties.");
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdProtocol), "zzdProtocol can't be blank, check your application.properties.");
        Preconditions.checkState(StrUtil.isNotBlank(zzdConfig.zzdTenantId), "zzdProtocol can't be blank, check your application.properties.");
        this.zzdLoginClient = ExecutableClient.getInstance();
        this.zzdLoginClient.setAccessKey(zzdConfig.zzdLoginAccessKey);
        this.zzdLoginClient.setSecretKey(zzdConfig.zzdLoginSecretKey);
        this.zzdLoginClient.setDomainName(zzdConfig.zzdDomainName);
        this.zzdLoginClient.setProtocal(zzdConfig.zzdProtocol);
        this.zzdLoginClient.init();
        this.zzdClient = ExecutableClient.getInstance();
        this.zzdClient.setAccessKey(zzdConfig.zzdAccessKey);
        this.zzdClient.setSecretKey(zzdConfig.zzdSecretKey);
        this.zzdLoginClient.setDomainName(zzdConfig.zzdDomainName);
        this.zzdLoginClient.setProtocal(zzdConfig.zzdProtocol);
        this.zzdClient.init();
    }

    public ZzdResponse<ZzdContent<AccessToken>> getLoginAccessToken() {
        GetClient getClient = this.zzdLoginClient.newGetClient(ZzdGlobalConfig.ZZD_TAKE_ACCESS_TOKEN_API);
        getClient.addParameter("appkey", this.zzdConfig.zzdLoginAccessKey);
        getClient.addParameter("appsecret", this.zzdConfig.zzdLoginSecretKey);
        String apiResult = getClient.get();
        log.info("Get login access token result:{}", apiResult);
        ZzdResponse<ZzdContent<AccessToken>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<AccessToken>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<AccessToken>> getAccessToken() {
        GetClient getClient = this.zzdLoginClient.newGetClient(ZzdGlobalConfig.ZZD_TAKE_ACCESS_TOKEN_API);
        getClient.addParameter("appkey", this.zzdConfig.zzdAccessKey);
        getClient.addParameter("appsecret", this.zzdConfig.zzdSecretKey);
        String apiResult = getClient.get();
        log.info("Get access token result:{}", apiResult);
        ZzdResponse<ZzdContent<AccessToken>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<AccessToken>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<ZzdUserAccount>> getUserInfo(GetZzdUserDto dto) {
        GetClient getClient = this.zzdLoginClient.newGetClient(ZzdGlobalConfig.ZZD_GET_USER_INFO_API);
        getClient.addParameter("access_token", dto.getAccessToken());
        getClient.addParameter("code", dto.getCode());
        String apiResult = getClient.get();
        log.info("Get user info result:{}", apiResult);
        ZzdResponse<ZzdContent<ZzdUserAccount>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<ZzdUserAccount>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<AddressBookScope> getScopesV2() {
        GetClient getClient = this.zzdClient.newGetClient(ZzdGlobalConfig.ZZD_GET_ADDRESS_BOOK_SCOPE_API);
        getClient.addParameter("tenantId", this.zzdConfig.zzdTenantId);
        String apiResult = getClient.get();
        log.info("Get scope v2 result:{}", apiResult);
        ZzdResponse<AddressBookScope> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<AddressBookScope>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<List<String>>> pageSubOrganizationCodes(Integer pageSize, Integer pageNo, String orgCode) {
        String tenantId = this.zzdConfig.zzdTenantId;
        Preconditions.checkNotNull(pageSize, "pageSize can't be null.");
        Preconditions.checkNotNull(pageNo, "pageNo can't be null.");
        Preconditions.checkState(StrUtil.isNotBlank(orgCode), "orgCode can't be null.");
        Preconditions.checkState(StrUtil.isNotBlank(tenantId), "tenantId can't be null.");
        GetClient getClient = this.zzdClient.newGetClient(ZzdGlobalConfig.ZZD_GET_SUB_ORG_CODES_BY_PAGE_API);
        getClient.addParameter("tenantId", tenantId);
        getClient.addParameter("returnTotalSize", "true");
        getClient.addParameter("pageSize", pageSize.toString());
        getClient.addParameter("pageNo", pageNo.toString());
        getClient.addParameter("organizationCode", orgCode);
        getClient.addParameter("status", QueryStatus.TOTAL.toString());
        String apiResult = getClient.get();
        log.info("Get sub org codes by page result:{}", apiResult);
        ZzdResponse<ZzdContent<List<String>>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<List<String>>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<List<ZzdOrganization>>> listOrganizationsByCodes(String orgCode) {
        Preconditions.checkState(StrUtil.isNotBlank(orgCode), "orgCode can't be null.");
        GetClient getClient = this.zzdClient.newGetClient(ZzdGlobalConfig.ZZD_GET_SUB_ORG_BY_CODE);
        getClient.addParameter("tenantId", this.zzdConfig.zzdTenantId);
        getClient.addParameter("organizationCodes", orgCode);
        String apiResult = getClient.get();
        log.info("Get org detail by codes result:{}", apiResult);
        ZzdResponse<ZzdContent<List<ZzdOrganization>>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<List<ZzdOrganization>>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<List<ZzdEmployee>>> pageOrganizationEmployeePositions(Integer pageSize, Integer pageNo, String orgCode) {
        Preconditions.checkNotNull(pageSize, "pageSize can't be null.");
        Preconditions.checkNotNull(pageNo, "pageNo can't be null.");
        Preconditions.checkState(StrUtil.isNotBlank(orgCode), "orgCode can't be blank.");
        GetClient getClient = this.zzdClient.newGetClient(ZzdGlobalConfig.ZZD_GET_USER_BY_ORG);
        getClient.addParameter("tenantId", this.zzdConfig.zzdTenantId);
        getClient.addParameter("returnTotalSize", "true");
        getClient.addParameter("pageSize", pageSize.toString());
        getClient.addParameter("pageNo", pageNo.toString());
        getClient.addParameter("organizationCode", orgCode);
        String apiResult = getClient.get();
        log.info("Page employee by orgCode result:{}", apiResult);
        ZzdResponse<ZzdContent<List<ZzdEmployee>>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<List<ZzdEmployee>>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<List<ZzdAccount>>> listEmployeeAccountIds(String employeeCode) {
        Preconditions.checkState(StrUtil.isNotBlank(employeeCode), "employeeCode can't be blank.");
        GetClient getClient = this.zzdClient.newGetClient(ZzdGlobalConfig.ZZD_GET_ACCOUNT_BY_EMPLOYEE_CODE);
        getClient.addParameter("tenantId", this.zzdConfig.zzdTenantId);
        getClient.addParameter("employeeCodes", employeeCode);
        String apiResult = getClient.get();
        log.info("Get account info by employee code result:{}", apiResult);
        ZzdResponse<ZzdContent<List<ZzdAccount>>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<List<ZzdAccount>>>>() {
        }, new Feature[0]);
        return zzdResponse;
    }

    public ZzdResponse<ZzdContent<ZzdUserAccount>> getDingtalkAppUser(String authCode) {
        Preconditions.checkState(StrUtil.isNotBlank(authCode), "Auth code can't be blank.");
        ZzdResponse<ZzdContent<AccessToken>> accessTokenResp = this.getAccessToken();
        if (accessTokenResp != null && accessTokenResp.getContent() != null && ((ZzdContent) accessTokenResp.getContent()).getData() != null) {
            PostClient getClient = this.zzdLoginClient.newPostClient(ZzdGlobalConfig.ZZD_GET_APP_USER_INFO_API);
            getClient.addParameter("access_token", ((AccessToken) ((ZzdContent) accessTokenResp.getContent()).getData()).getAccessToken());
            getClient.addParameter("auth_code", authCode);
            String apiResult = getClient.post();
            log.info("Get dingtalk appUser info by auth code result:{}", apiResult);
            ZzdResponse<ZzdContent<ZzdUserAccount>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<ZzdUserAccount>>>() {
            }, new Feature[0]);
            return zzdResponse;
        } else {
            throw new RuntimeException("Get access token failed, get ding talk app user failed.");
        }
    }

    public ZzdResponse<ZzdContent<ZzdTicket>> getJsApiTicket() {
        ZzdResponse<ZzdContent<AccessToken>> accessTokenResp = this.getAccessToken();
        if (accessTokenResp != null && accessTokenResp.getContent() != null && ((ZzdContent) accessTokenResp.getContent()).getData() != null) {
            GetClient getClient = this.zzdClient.newGetClient(ZzdGlobalConfig.ZZD_GET_JS_TICKET_API);
            getClient.addParameter("accessToken", ((AccessToken) ((ZzdContent) accessTokenResp.getContent()).getData()).getAccessToken());
            String apiResult = getClient.get();
            log.info("Get js api ticket result:{}", apiResult);
            ZzdResponse<ZzdContent<ZzdTicket>> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent<ZzdTicket>>>() {
            }, new Feature[0]);
            return zzdResponse;
        } else {
            throw new RuntimeException("Get access resp failed");
        }
    }

    public OapiTcV2OpenapiTaskCreateJsonResponse createTask(CreateTaskDto dto) {
        Preconditions.checkNotNull(dto, "Create task dto can't be null");
        Preconditions.checkState(StrUtil.isNotBlank(dto.getSubject()), "Subject can't be blank.");
        Preconditions.checkState(StrUtil.isNotBlank(dto.getAssigneeId()), "Assignee id can't be blank.");
        Preconditions.checkState(StrUtil.isNotBlank(dto.getCreateUserName()), "Create user name can't be blank.");
        Preconditions.checkState(StrUtil.isNotBlank(dto.getCreateUserId()), "Create user id can't be blank.");
        IntelligentGetClient intelligentGetClient = this.zzdClient.newIntelligentGetClient(ZzdGlobalConfig.ZZD_CREATE_TASK);
        OapiTcV2OpenapiTaskCreateJsonRequest oapiTcV2OpenapiTaskCreateJsonRequest = new OapiTcV2OpenapiTaskCreateJsonRequest();
        oapiTcV2OpenapiTaskCreateJsonRequest.setSubject(dto.getSubject());
        oapiTcV2OpenapiTaskCreateJsonRequest.setCreatorId(dto.getCreateUserId());
        oapiTcV2OpenapiTaskCreateJsonRequest.setAssigneeId(dto.getAssigneeId());
        oapiTcV2OpenapiTaskCreateJsonRequest.setUrl(dto.getUrl());
        oapiTcV2OpenapiTaskCreateJsonRequest.setTenantId(this.zzdConfig.zzdTenantId);
        oapiTcV2OpenapiTaskCreateJsonRequest.setBizTaskId(UUID.randomUUID().toString().replaceAll("-", ""));
        oapiTcV2OpenapiTaskCreateJsonRequest.setMobileUrl(dto.getMobileUrl());
        OapiTcV2OpenapiTaskCreateJsonResponse apiResult = (OapiTcV2OpenapiTaskCreateJsonResponse) intelligentGetClient.get(oapiTcV2OpenapiTaskCreateJsonRequest);
        return apiResult;
    }

    public OapiCalendarCreateCalendarResponse createCalendar() {
        PostClient getClient = this.zzdClient.newPostClient("/calendar/createCalendar");
        getClient.addParameter("tenantId", this.zzdConfig.zzdTenantId);
        getClient.addParameter("accountId", "765382");
        getClient.addParameter("creator", "{\"accountId\":\"765382\"}");
        getClient.addParameter("start", "{\"timeStamp\":" + System.currentTimeMillis() + "}");
        getClient.addParameter("end", "{\"timeStamp\":" + System.currentTimeMillis() + 100000 + "}");
        getClient.addParameter("eventType", "conference");
        getClient.addParameter("event", "{\"location\": \"西湖断桥\",\"subject\": \"白娘子和许仙\",\"meetingTypeName\": \"常务会议\",\"sponsoringDepartment\": \"政法委\",\"description\": \"如何搭讪许仙\",\"otherAttendees\": \"洛迦山-观音菩萨，灵霄宝殿-王母娘娘\",\"meetingRoom\": \"西湖画舫2-1-35\"}");
        getClient.addParameter("attendees", "[{\"accountId\": 765382,\"attendeeType\": \"employee\"},{\"accountId\": 766701,\"attendeeType\": \"employee\"}]");
        String apiResult = getClient.post();
        log.info("Create calendar  result:{}", apiResult);
        ZzdResponse<ZzdContent> zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, new TypeReference<ZzdResponse<ZzdContent>>() {
        }, new Feature[0]);
        return null;
    }

    public OapiChatSendMsgResponse sendChatMessage(SendChatMessageDto dto) {
        IntelligentGetClient intelligentGetClient = this.zzdClient.newIntelligentGetClient(ZzdGlobalConfig.ZZD_SEND_CHAT_MESSAGE);
        OapiChatSendMsgRequest oapiChatSendMsgRequest = new OapiChatSendMsgRequest();
        oapiChatSendMsgRequest.setMsg(JSON.toJSONString(new ZzdTextMessage(dto.getMessage())));
        oapiChatSendMsgRequest.setSenderId(dto.getSenderId());
        oapiChatSendMsgRequest.setReceiverId(dto.getReceiverId());
        oapiChatSendMsgRequest.setTenantId(Long.parseLong(this.zzdConfig.zzdTenantId));
        oapiChatSendMsgRequest.setChatType(ChatType.single_chat.getValue());
        OapiChatSendMsgResponse apiResult = (OapiChatSendMsgResponse) intelligentGetClient.get(oapiChatSendMsgRequest);
        return apiResult;
    }

    public OapiChatGroupV2CreateResponse createChatGroup(CreateGroupDto dto) {
        Preconditions.checkNotNull(dto, "Create chat group dto can't be null");
        Preconditions.checkState(StrUtil.isNotBlank(dto.getGroupName()), "Group name can't be blank.");
        Preconditions.checkState(!CollectionUtils.isEmpty(dto.getAccountList()), "Account list can't be blank.");
        IntelligentGetClient intelligentGetClient = this.zzdClient.newIntelligentGetClient(ZzdGlobalConfig.ZZD_CREATE_CHAT_GROUP);
        OapiChatGroupV2CreateRequest oapiChatGroupV2CreateRequest = new OapiChatGroupV2CreateRequest();
        oapiChatGroupV2CreateRequest.setAccountId(Long.parseLong(dto.getCreateUserId()));
        oapiChatGroupV2CreateRequest.setTenantId(Long.parseLong(this.zzdConfig.zzdTenantId));
        oapiChatGroupV2CreateRequest.setUseridlist(dto.getAccountList());
        oapiChatGroupV2CreateRequest.setName(dto.getGroupName());
        oapiChatGroupV2CreateRequest.setManagementType(GroupManagementType.open.getValue());
        OapiChatGroupV2CreateResponse apiResult = (OapiChatGroupV2CreateResponse) intelligentGetClient.get(oapiChatGroupV2CreateRequest);
        return apiResult;
    }

    public ZzdResponse getData(String api, List<Pair<String, String>> params) {
        Preconditions.checkState(StrUtil.isNotBlank(api), "api can't be blank.");
        GetClient getClient = this.zzdClient.newGetClient(api);
        if (!CollectionUtils.isEmpty(params)) {
            Iterator var4 = params.iterator();

            while (var4.hasNext()) {
                Pair<String, String> pair = (Pair) var4.next();
                String value = (String) pair.getValue();
                getClient.addParameter((String) pair.getKey(), value);
            }
        }

        String apiResult = getClient.get();
        log.info("Get account info by employee code result:{}", apiResult);
        ZzdResponse zzdResponse = (ZzdResponse) JSON.parseObject(apiResult, ZzdResponse.class);
        return zzdResponse;
    }
}


